using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XFABManager;


namespace XFGameFramework
{

    public enum TimerType {
        Frame,
        Time
    }

    public class Timer 
    { 
        #region 字段

        internal TimerType type;
        internal Action callback;
        internal float time;
        internal bool ignoreTimeScale;
        internal int frameCount; 

        private GameObject gameObject;

        private bool bindingWithGameObject;

        internal bool repeat;

        internal float interval;
        internal float current_interval;

        internal int repeat_count;

        internal bool isValid;

         
        #endregion

        #region 属性

        private DisableListener DisableListener
        {
            get 
            {
                if (!gameObject)
                    return null;

                DisableListener listener = gameObject.GetComponent<DisableListener>();

                if (listener == null)
                    listener = gameObject.AddComponent<DisableListener>();

                return listener;
            }
        }

        #endregion


        #region 方法
         
        internal void BindGameObject(GameObject gameObject)
        {
            isValid = true;
            repeat = false;

            this.gameObject = gameObject;
            bindingWithGameObject = gameObject;

            if (bindingWithGameObject) 
            {
                if (DisableListener) 
                { 
                    DisableListener.onDisable.RemoveListener(OnDisable);
                    DisableListener.onDisable.AddListener(OnDisable);  
                } 
            }

        }

        private void OnDisable() 
        {
            if(DisableListener)
                DisableListener.onDisable.RemoveListener(OnDisable);
             
            gameObject = null;
            Abort();
        }

        /// <summary>
        /// 中断
        /// </summary>
        public void Abort() 
        {
            // 中断的话直接设置成无效即可
            isValid = false;
        }

        internal void Invoke(bool remove = true) 
        {
            try
            {
                callback?.Invoke(); 
            }
            catch (Exception e)
            {
                Debug.LogException(e);
            }


            // 把isValid设置为false , 会认为该延迟任务无效，进而把它移除
            if (remove) 
            {             
                // 触发之后设置成无效 避免重复触发
                isValid = false;
            }
        }

         

        internal bool IsValid() 
        {
            if (bindingWithGameObject) 
            {
                if(!gameObject || !gameObject.activeInHierarchy)
                    return false; 
            }
            return isValid;
        }

        internal void Update() 
        { 
            switch (type)
            {
                case TimerType.Frame:

                    frameCount--;

                    if (frameCount <= -1)
                        Invoke();


                    break;
                case TimerType.Time:

                    if (repeat)
                    {
                        if (time > 0)
                        {
                            time -= TimeExtensions.GetDeltaTime(ignoreTimeScale);
                            if (time <= 0)
                                 Invoke(false);
                        }
                        else 
                        {
                            current_interval -= TimeExtensions.GetDeltaTime(ignoreTimeScale);
                            if (current_interval <= 0) 
                            {
                                Invoke(false);
                                current_interval = interval;

                                // 如果等于-1 一直重复
                                if (repeat_count != -1) 
                                {
                                    repeat_count--;
                                    if(repeat_count <= 0)
                                        isValid = false;
                                }

                            }
                        }

                    }
                    else 
                    { 
                        time -= TimeExtensions.GetDeltaTime(ignoreTimeScale);
                        if (time <= 0)
                            Invoke();
                    }

                    break; 
            }
        }

        #endregion

    }

    public class TimerManager : MonoBehaviour
    {

        #region 静态字段

        private static TimerManager _instance;

        #endregion

        #region 静态属性

        private static TimerManager Instance 
        {
            get 
            {
                if (!_instance && ApplicationTool.isPlaying) 
                {
                    GameObject obj = new GameObject(typeof(TimerManager).Name);
                    DontDestroyOnLoad(obj);
                    _instance = obj.AddComponent<TimerManager>();
                }

                return _instance;
            }

        }

        #endregion

        #region 字段

        private List<Timer> timers = new List<Timer>();

        //private Dictionary<int,Timer> timers = new Dictionary<int, Timer>();

        #endregion

        #region 生命周期

        private void Update()
        {
            for (int i = timers.Count - 1; i >= 0; i--) 
            {
                if (!timers[i].IsValid())
                { 
                    timers.RemoveAt(i); 
                }
                else
                {  
                    timers[i].Update();
                } 
            }
        }
        
        #endregion

      
        #region 方法
         
        /// <summary>
        /// 延迟调用
        /// </summary>
        /// <param name="callback">回调方法</param>
        /// <param name="time">延迟时间</param>
        /// <param name="ignoreTimeScale">是否忽略时间缩放</param>
        /// <returns></returns>
        public static Timer DelayInvoke(Action callback,float time,bool ignoreTimeScale = true) 
        { 
            return DelayInvoke(null,callback,time,ignoreTimeScale);
        }

        /// <summary>
        /// 延迟调用(绑定GameObject)
        /// </summary>
        /// <param name="gameObject">绑定的GameObject,如果GameObject被销毁或处于非活跃状态,自动取消延迟调用</param>
        /// <param name="callback">回调方法</param>
        /// <param name="time">延迟时间</param>
        /// <param name="ignoreTimeScale">是否忽略时间缩放</param>
        /// <returns></returns>
        public static Timer DelayInvoke(GameObject gameObject,Action callback, float time, bool ignoreTimeScale = true)
        { 
            if (!Instance) return default;

            Timer timer = new Timer();
             
            timer.BindGameObject(gameObject);

            timer.callback = callback;
            timer.ignoreTimeScale = ignoreTimeScale;
            timer.time = time;
            timer.type = TimerType.Time;
            Instance.timers.Add(timer); 
            return timer;
        }

        /// <summary>
        /// 延迟一帧调用
        /// </summary>
        /// <param name="callback">回调方法</param>
        /// <returns></returns>
        public static Timer DelayFrame(Action callback) 
        {  
            return DelayFrame(null, callback);
        }

        /// <summary>
        /// 延迟一帧调用(绑定GameObject)
        /// </summary>
        /// <param name="gameObject">绑定的GameObject,如果GameObject被销毁或处于非活跃状态,自动取消延迟调用</param>
        /// <param name="callback">回调方法</param>
        /// <returns></returns>
        public static Timer DelayFrame(GameObject gameObject,Action callback)
        {
            return DelayFrame(gameObject, callback, 1);
        }

        /// <summary>
        /// 延迟指定帧数调用
        /// </summary>
        /// <param name="callback">回调方法</param>
        /// <param name="frameCount">延迟的帧数</param>
        /// <returns></returns>
        public static Timer DelayFrame(Action callback,int frameCount)
        {  
            return DelayFrame(null,callback,frameCount);
        }

        /// <summary>
        /// 延迟指定帧数调用(绑定GameObject)
        /// </summary>
        /// <param name="gameObject">绑定的GameObject,如果GameObject被销毁或处于非活跃状态,自动取消延迟调用</param>
        /// <param name="callback">回调方法</param>
        /// <param name="frameCount">延迟的帧数</param>
        /// <returns></returns>
        public static Timer DelayFrame(GameObject gameObject,Action callback, int frameCount)
        {
            if (!Instance) return default;
            Timer timer = new Timer();
            timer.BindGameObject(gameObject);

            timer.callback = callback;
            timer.ignoreTimeScale = false;
            timer.time = 0;
            timer.type = TimerType.Frame;
            timer.frameCount = frameCount;
            //timer.gameObject = gameObject;
            //timer.bindingWithGameObject = gameObject;
            Instance.timers.Add(timer);

            return timer;
        }

        /// <summary>
        /// 重复调用
        /// </summary>
        /// <param name="callback">回调方法</param>
        /// <param name="delay">延迟时间</param>
        /// <param name="interval">重复调用的时间间隔</param>
        /// <param name="ignoreTimeScale">是否忽略时间缩放</param>
        /// <returns></returns>
        public static Timer RepeatInvoke(Action callback, float delay,float interval, bool ignoreTimeScale = true) 
        { 
            return RepeatInvoke(callback,delay,interval, -1 ,ignoreTimeScale);
        }

        /// <summary>
        /// 重复调用(指定重复次数)
        /// </summary>
        /// <param name="callback">回调方法</param>
        /// <param name="delay">延迟时间</param>
        /// <param name="interval">重复调用的时间间隔</param>
        /// <param name="repeat_count">重复调用次数</param>
        /// <param name="ignoreTimeScale">是否忽略时间缩放</param>
        /// <returns></returns>
        public static Timer RepeatInvoke(Action callback, float delay, float interval, int repeat_count,bool ignoreTimeScale = true) 
        {
            return RepeatInvoke(null, callback, delay, interval, repeat_count, ignoreTimeScale);
        }

        /// <summary>
        /// 重复调用(绑定GameObject)
        /// </summary>
        /// <param name="gameObject">绑定的GameObject,如果GameObject被销毁或处于非活跃状态,自动取消延迟调用</param>
        /// <param name="callback">回调方法</param>
        /// <param name="delay">延迟时间</param>
        /// <param name="interval">重复调用的时间间隔</param>
        /// <param name="ignoreTimeScale">是否忽略时间缩放</param>
        /// <returns></returns>
        public static Timer RepeatInvoke(GameObject gameObject, Action callback, float delay, float interval, bool ignoreTimeScale = true) {

            return RepeatInvoke(gameObject, callback, delay, interval, -1,ignoreTimeScale);
        }

        /// <summary>
        /// 重复调用(绑定GameObject 并 指定重复次数)
        /// </summary>
        /// <param name="gameObject">绑定的GameObject,如果GameObject被销毁或处于非活跃状态,自动取消延迟调用</param>
        /// <param name="callback">回调方法</param>
        /// <param name="delay">延迟时间</param>
        /// <param name="interval">重复调用的时间间隔</param>
        /// <param name="repeat_count">重复调用次数</param>
        /// <param name="ignoreTimeScale">是否忽略时间缩放</param>
        /// <returns></returns>
        public static Timer RepeatInvoke(GameObject gameObject, Action callback, float delay, float interval,int repeat_count, bool ignoreTimeScale = true)
        {
            if (!Instance) return default;
            Timer timer = new Timer();
            timer.BindGameObject(gameObject);

            timer.callback = callback;
            timer.ignoreTimeScale = ignoreTimeScale;
            timer.time = delay;
            timer.interval = interval;
            timer.current_interval = interval;
            timer.type = TimerType.Time; 
            //timer.gameObject = gameObject;
            //timer.bindingWithGameObject = gameObject;
            timer.repeat = true;
            timer.repeat_count = repeat_count;
            Instance.timers.Add(timer);
            return timer;
        }


        /// <summary>
        /// 等待协程执行结束后执行
        /// </summary>
        /// <param name="coroutine">协程对象</param>
        /// <param name="onFinsh">回调</param>
        public static void WaitForCoroutine(Coroutine coroutine, Action onFinsh)
        {
            CoroutineStarter.Start(WaitForCoroutineExcute(coroutine, onFinsh));
        }

        private static IEnumerator WaitForCoroutineExcute(Coroutine coroutine, Action onFinsh)
        {
            yield return coroutine;
            onFinsh?.Invoke();
        }

      
        #endregion

    }

}